using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;

namespace RBSViewer
{
    public class MultiSelectTree : System.Windows.Forms.TreeView
    {
        private TreeNode lastNode;
        private ArrayList selectedNodes;
        private TreeNode firstNode;
        public Boolean MultiSelect;

 
        public MultiSelectTree()
        {
            selectedNodes = new ArrayList();
            MultiSelect = true;
        }

        public ArrayList SelectedNodes
        {
            get
            {
                return selectedNodes;
            }
            set
            {
                DeselectNodes();
                selectedNodes.Clear();
                selectedNodes = value;
                SelectNodes();
            }
        }

        protected override void OnKeyUp(KeyEventArgs e)
        {
            base.OnKeyDown(e);
            bool Pressed = (e.Control && ((e.KeyData & Keys.A) == Keys.A));
            if (Pressed)
            {
                SelectAllNodes(this.Nodes);
            }
        }

        protected override void OnBeforeSelect(TreeViewCancelEventArgs e)
        {
            base.OnBeforeSelect(e);

            bool isControlPressed = false;
            bool isShiftPressed = false;
            if(MultiSelect)
            {
                isControlPressed  = (ModifierKeys == Keys.Control);
                isShiftPressed = (ModifierKeys == Keys.Shift);
            }

            if (isControlPressed && selectedNodes.Contains(e.Node))
            {
                DeselectNodes();
                selectedNodes.Remove(e.Node);
                SelectNodes();
                e.Cancel = true;
                return;
            }

            lastNode = e.Node;

            if (!isShiftPressed) firstNode = e.Node;
        }

        protected override void OnAfterSelect(TreeViewEventArgs e)
        {
            base.OnAfterSelect(e);

            bool isControlPressed = false;
            bool isShiftPressed = false;
            if (MultiSelect)
            {
                isControlPressed = (ModifierKeys == Keys.Control);
                isShiftPressed = (ModifierKeys == Keys.Shift);
            }

            if (isControlPressed)
            {
                if (!selectedNodes.Contains(e.Node))
                {
                    selectedNodes.Add(e.Node);
                }
                else
                {
                    DeselectNodes();
                    selectedNodes.Remove(e.Node);
                }
                SelectNodes();
            }
            else
            {
                if (isShiftPressed)
                {
                    TreeNode uppernode = firstNode;
                    TreeNode bottomnode = e.Node;
                    bool bParent = CheckIfParent(uppernode, bottomnode);
                    if (!bParent)
                    {
                        bParent = CheckIfParent(bottomnode, uppernode);
                        if (bParent) 
                        {
                            TreeNode temp = uppernode;
                            uppernode = bottomnode;
                            bottomnode = temp;
                        }
                    }
                    if (bParent)
                    {
                        TreeNode n = bottomnode;
                        while (n != uppernode.Parent)
                        {
                            if (!selectedNodes.Contains(n))
                                selectedNodes.Add(n);
                            n = n.Parent;
                        }
                    }

                    else
                    {
                        if ((uppernode.Parent == null && bottomnode.Parent == null) || (uppernode.Parent != null && uppernode.Parent.Nodes.Contains(bottomnode))) // are they siblings ?
                        {
                            int nIndexUpper = uppernode.Index;
                            int nIndexBottom = bottomnode.Index;

                            if (nIndexBottom < nIndexUpper)
                            {
                                TreeNode temp = uppernode;
                                uppernode = bottomnode;
                                bottomnode = temp;
                                nIndexUpper = uppernode.Index;
                                nIndexBottom = bottomnode.Index;
                            }

                            TreeNode n = uppernode;
                            selectedNodes.Clear();
                            while (nIndexUpper < nIndexBottom)
                            {
                                if (!selectedNodes.Contains(n))
                                {
                                    selectedNodes.Add(n);
                                    SelectAllNodesInNode(n.Nodes, n);
                                }
                                n = n.NextNode;
                                nIndexUpper++;
                            }
                            selectedNodes.Add(n);
                        }
                        else
                        {
                            if (!selectedNodes.Contains(uppernode)) selectedNodes.Add(uppernode);
                            if (!selectedNodes.Contains(bottomnode)) selectedNodes.Add(bottomnode);
                        }
                    }
                    SelectNodes();
                    firstNode = e.Node;
                }
                else
                {
                    if (selectedNodes != null && selectedNodes.Count > 0)
                    {
                        DeselectNodes();
                        selectedNodes.Clear();
                    }
                    selectedNodes.Add(e.Node);
                }
            }
        }

        protected override void OnLostFocus(EventArgs e)
        {
            base.OnLostFocus(e);
            DeselectNodes();
        }

        protected override void OnGotFocus(EventArgs e)
        {
            base.OnGotFocus(e);
            SelectNodes();
        }

        private bool CheckIfParent(TreeNode parentNode, TreeNode childNode)
        {
            if (parentNode == childNode)
                return true;

            TreeNode node = childNode;
            bool parentFound = false;
            while (!parentFound && node != null)
            {
                node = node.Parent;
                parentFound = (node == parentNode);
            }
            return parentFound;
        }

        private void SelectNodes()
        {
            foreach (TreeNode n in selectedNodes)
            {
                n.BackColor = SystemColors.Highlight;
                n.ForeColor = SystemColors.HighlightText;
            }
        }

        private void DeselectNodes()
        {
            if (selectedNodes.Count == 0) return;

            TreeNode node = (TreeNode)selectedNodes[0];
            Color backColor = node.TreeView.BackColor;
            Color foreColor = node.TreeView.ForeColor;

            foreach (TreeNode n in selectedNodes)
            {
                n.BackColor = backColor;
                n.ForeColor = foreColor;
            }

        }

        private void SelectAllNodes(TreeNodeCollection nodes)
        {
            foreach (TreeNode n in this.Nodes)
            {
                selectedNodes.Add(n);
                if (n.Nodes.Count > 1)
                {
                    SelectAllNodesInNode(n.Nodes, n);
                }

            }
            SelectNodes();
        }

        private void SelectAllNodesInNode(TreeNodeCollection nodes, TreeNode node)
        {
            foreach (TreeNode n in node.Nodes)
            {
                selectedNodes.Add(n);
                if (n.Nodes.Count > 1)
                {
                    SelectAllNodesInNode(n.Nodes, n);
                }
            }
            SelectNodes();
        }

    }
}
